home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Chans / smtp / smtpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  7.3 KB  |  381 lines

  1. /* smtpd: daemon for smtp */
  2.  
  3. # ifndef lint
  4. static char Rcsid[] = "@(#)$Header: /xtel/pp/pp-beta/Chans/smtp/RCS/smtpd.c,v 6.0 1991/12/18 20:12:19 jpo Rel $";
  5. # endif
  6.  
  7. /*
  8.  * $Header: /xtel/pp/pp-beta/Chans/smtp/RCS/smtpd.c,v 6.0 1991/12/18 20:12:19 jpo Rel $
  9.  *
  10.  * $Log: smtpd.c,v $
  11.  * Revision 6.0  1991/12/18  20:12:19  jpo
  12.  * Release 6.0
  13.  *
  14.  */
  15.  
  16.  
  17.  
  18. /*
  19.  * new version - detects if it is running under inetd.
  20.  */
  21.  
  22.  
  23. #include "util.h"
  24. #include <signal.h>
  25. #include "sys.file.h"
  26. #ifdef  SYS5
  27. #ifdef vfork
  28. #undef vfork
  29. #endif
  30. #include <unistd.h>
  31. #endif
  32. #include <sys/signal.h>
  33. #include <isode/internet.h>
  34. #include <sys/wait.h>
  35. #include <sys/ioctl.h>
  36. #include <errno.h>
  37. #ifdef SYS5
  38. #include <sys/resource.h>
  39. #endif
  40.  
  41. static char usage[] = "usage: smptd [-p port] [-i maxconn] \
  42. program channel";
  43.  
  44. static int smtpport;
  45. static int    maxconn = 5;
  46. static struct sockaddr_in rmtaddr, laddr;
  47. static int    numconnections = 0;
  48. static char thishost[LINESIZE];
  49. static char *Channel, Smtpserver[BUFSIZ];
  50. static char *nstimeout;
  51.  
  52. static void envinit ();
  53. static SFD reaper ();
  54.  
  55. #if sparc && defined(__GNUC__)    /* work around bug in gcc 1.37 sparc version */
  56. #define inet_ntoa myinet_ntoa
  57.  
  58. static char *myinet_ntoa (in)
  59. struct in_addr in;
  60. {
  61.     static char buf[80];
  62.  
  63.     (void) sprintf (buf, "%d.%d.%d.%d",
  64.             (in.s_addr >> 24) & 0xff,
  65.             (in.s_addr >> 16) & 0xff,
  66.             (in.s_addr >> 8 ) & 0xff,
  67.             (in.s_addr    ) & 0xff);
  68.     return buf;
  69. }
  70. #else
  71. extern char    *inet_ntoa ();
  72. #endif
  73.  
  74. extern int errno;
  75.  
  76. char    *myname;
  77. int    debug;
  78.  
  79. main (argc, argv)
  80. int    argc;
  81. char    **argv;
  82. {
  83.     extern char    *optarg;
  84.     extern int    optind;
  85.     int    opt;
  86.     struct servent *sp;
  87.     int    alen, i, skt;
  88.  
  89.     myname = argv[0];
  90.     sys_init (myname);
  91.  
  92.     if ((sp = getservbyname ("smtp", "tcp")) == NULL)
  93.         smtpport = htons (25);
  94.     else    smtpport = sp -> s_port;
  95.  
  96.     while((opt = getopt(argc, argv, "p:i:t:")) != EOF)
  97.         switch (opt) {
  98.             case 'i':
  99.             maxconn = atoi (optarg);
  100.             break;
  101.             case 'p':
  102.             smtpport = htons ((short)atoi (optarg));
  103.             break;
  104.             case 't':
  105.             nstimeout = optarg;
  106.             break;
  107.             default:
  108.             fprintf (stderr, "bad switch -%c: %s\n", opt, usage);
  109.             PP_OPER (NULLCP, ("Bad argument -%c: %s", opt, usage));
  110.             exit (1);
  111.         }
  112.     argc -= optind;
  113.     argv += optind;
  114.  
  115.     initialise (argc, argv);
  116.  
  117.     alen = sizeof rmtaddr;
  118.     if (getpeername (0, (struct sockaddr *)&rmtaddr,
  119.              &alen) == 0) { /* under inetd */
  120.         PP_TRACE (("Running under inetd..."));
  121.         doit (0);
  122.         _exit (0);
  123.     }
  124.  
  125.     envinit ();
  126.  
  127.     laddr.sin_family = AF_INET;
  128.     laddr.sin_addr.s_addr = INADDR_ANY;
  129.     laddr.sin_port = smtpport;
  130.  
  131.     for (i = 0; i < 10; sleep ((unsigned) 2 * ++i)) {
  132.         if ((skt = socket (AF_INET, SOCK_STREAM, 0)) == -1) {
  133.             PP_SLOG (LLOG_EXCEPTIONS, "socket",
  134.                  ("can't create "));
  135.             continue;
  136.         }
  137.  
  138.         if (bind (skt, (struct sockaddr *)&laddr,
  139.               sizeof laddr) == -1) {
  140.             PP_SLOG (LLOG_EXCEPTIONS, "bind",
  141.                  ("socket can't "));
  142.             (void) close (skt);
  143.             continue;
  144.         }
  145.  
  146.         if (listen (skt, 5) == -1) {
  147.             PP_SLOG (LLOG_EXCEPTIONS, "listen",
  148.                  ("socket can't "));
  149.             (void) close (skt);
  150.             continue;
  151.         }
  152.         break;
  153.     }
  154.  
  155.     PP_NOTICE (("%s listening on port %d", myname, ntohs(smtpport)));
  156. #define tcp_still_alive_and_kicking 1
  157.  
  158.     while (tcp_still_alive_and_kicking) {
  159.         int    snew;
  160.         int    pid;
  161.  
  162.         alen = sizeof (rmtaddr);
  163.         if ((snew = accept (skt, (struct sockaddr *)&rmtaddr,
  164.                     &alen)) == NOTOK) {
  165.             if (errno != EINTR)
  166.                 PP_SLOG (LLOG_EXCEPTIONS, "failed",
  167.                      ("accept "));
  168.             continue;
  169.         }
  170.         PP_TRACE (("Accepted new connection from %s",
  171.                inet_ntoa (rmtaddr.sin_addr)));
  172.         if ((pid = tryfork ()) == NOTOK) {
  173.             PP_SLOG (LLOG_EXCEPTIONS, "failed", ("fork "));
  174.             sleep (10);
  175.             continue;
  176.         }
  177.         if (pid == 0) {    /* child */
  178.             doit (snew);
  179.             _exit(0);
  180.         }
  181.         (void) close (snew);
  182.  
  183.         numconnections ++;
  184.  
  185.         while (numconnections >= maxconn) {
  186.             PP_TRACE (("Too many connections -- waiting"));
  187. #ifdef SYS5
  188.             reaper(0);
  189. #else
  190.             sigpause (0);
  191. #endif
  192.             PP_TRACE (("Finished waiting"));
  193.         }
  194.     }
  195. }
  196.  
  197. /* ARGSUSED */
  198. static SFD reaper (sig)
  199. int sig;
  200. {
  201. #ifndef WNOHANG
  202.     int status;
  203.     alarm(2);
  204.     while (wait(&status) != -1)
  205.         numconnections --;
  206.     alarm (0);
  207. #else
  208. #ifdef SYS5
  209.     int status;
  210. #else
  211.     union wait status;
  212. #endif
  213.     while (wait3 (&status, WNOHANG, (caddr_t)0) > 0)
  214.         numconnections --;
  215. #endif
  216. }
  217.  
  218. #ifdef SYS5
  219. SFD alarmtrap (sig)
  220. int sig;
  221. {
  222.     (void) signal (SIGALRM, alarmtrap);
  223. }
  224. #endif
  225.  
  226. doit (fd)
  227. int    fd;
  228. {
  229.     char *argv[10];
  230.     int argc = 0;
  231.  
  232.     if (fd != 0)
  233.         (void) dup2 (fd, 0);
  234.     if (fd != 1)
  235.         (void) dup2 (fd, 1 );
  236.     if (fd != 2)
  237.         (void) dup2 (fd, 2 );
  238.     if (fd > 2 )
  239.         (void) close (fd);
  240.     argv[argc++] = Channel; /* argv[0] */
  241.     if (nstimeout) {
  242.         argv[argc++] = "-t";
  243.         argv[argc++] = nstimeout;
  244.     }
  245.     argv[argc++] = Channel;
  246.     argv[argc] = NULLCP;
  247.     execv (Smtpserver, argv);
  248.     PP_OPER (Smtpserver, ("server exec "));
  249.     _exit (99);
  250. }
  251.  
  252. static void  envinit () 
  253. {
  254.     int     i,
  255.         nbits,
  256.         sd;
  257.  
  258.     nbits = getdtablesize ();
  259.  
  260.     if (!(debug = isatty (2))) {
  261.         for (i = 0; i < 5; i++) {
  262.             switch (fork ()) {
  263.                 case NOTOK: 
  264.                 sleep (5);
  265.                 continue;
  266.  
  267.                 case OK: 
  268.                 break;
  269.  
  270.                 default: 
  271.                 _exit (0);
  272.             }
  273.             break;
  274.         }
  275.  
  276.         if ((sd = open ("/dev/null", O_RDWR)) == NOTOK) {
  277.             PP_OPER ("/dev/null", ("unable to read"));
  278.             exit (3);
  279.         }
  280.         if (sd != 0)
  281.             (void) dup2 (sd, 0), (void) close (sd);
  282.         (void) dup2 (0, 1);
  283.         (void) dup2 (0, 2);
  284.  
  285. #ifdef  TIOCNOTTY
  286.         if ((sd = open ("/dev/tty", O_RDWR)) != NOTOK) {
  287.             (void) ioctl (sd, TIOCNOTTY, NULLCP);
  288.             (void) close (sd);
  289.         }
  290. #else
  291. #ifdef  SYS5
  292.         (void) setpgrp ();
  293.         (void) signal (SIGINT, SIG_IGN);
  294.         (void) signal (SIGQUIT, SIG_IGN);
  295. #endif
  296. #endif
  297.     }
  298.     else
  299.         ll_dbinit (pp_log_norm, myname);
  300.  
  301. #ifdef notdef            /* damn YP... */
  302.     for (sd = 3; sd < nbits; sd++)
  303.         (void) close (sd);
  304. #endif
  305.  
  306.     (void) signal (SIGPIPE, SIG_IGN);
  307.  
  308.     ll_hdinit (pp_log_norm, myname);
  309. #ifndef SYS5
  310.     (void) signal (SIGCHLD, reaper);
  311. #endif
  312.  
  313.     PP_TRACE (("starting"));
  314. }
  315.  
  316. initialise (argc, argv)
  317. int    argc;
  318. char    **argv;
  319. {
  320.     int    i;
  321.     struct hostent *hp;
  322.     extern char *chndfldir;
  323.  
  324.     if (argc > 0)
  325.     {
  326.         getfpath (chndfldir, argv[0], Smtpserver);
  327.  
  328.         if (access (Smtpserver, X_OK) < 0 ) { /* execute privs? */
  329.             PP_OPER (Smtpserver, ("Cannot access server program"));
  330.             fprintf (stderr, "Cannot access server program %s\n",
  331.                  Smtpserver);
  332.             exit (99);
  333.         }
  334.         PP_TRACE (("server is '%s'", Smtpserver ));
  335.     } else {
  336.         fprintf (stderr, "Smtpserver program not specified! (%s)\n",
  337.              usage);
  338.         PP_OPER (NULLCP, ("Smtpserver program not specified! (%s)",
  339.                   usage));
  340.         exit (99);
  341.     }
  342.  
  343.     if( argc > 1 ) {
  344.         Channel = argv[1];
  345.         PP_TRACE (("channel is '%s'", Channel));
  346.     } else {
  347.         PP_OPER (NULLCP, ("Channel not specified! (%s)", usage));
  348.         fprintf (stderr, "Channel not specified! (%s)\n", usage);
  349.         exit (99);
  350.     }
  351.  
  352.         /*
  353.          * must get full name for this host from nameserver (or file)
  354.          */
  355.  
  356.     if (gethostname (thishost, sizeof thishost) == -1)
  357.         PP_SLOG (LLOG_EXCEPTIONS, "gethostname",
  358.              ("Can't find out who I am"));
  359.  
  360.         for(i = 0 ; i < 10 ; i++){
  361.                 hp = gethostbyname(thishost);
  362.                 if(hp != NULL)
  363.                         break;
  364.                 if(i > 2)
  365.                         sleep((unsigned)i*2);
  366.         }
  367.         if(hp == NULL) {
  368.         PP_OPER (NULLCP, 
  369.                   ("Cannot find 'official' name of host '%s'\n",
  370.                         thishost));
  371.                 fprintf(stderr,
  372.           "Cannot find 'official' name of host '%s'\n",
  373.                                                    thishost);
  374.                 exit(-1);
  375.         }
  376.         (void) strcpy(thishost, hp->h_name);
  377. #ifdef SYS5
  378.     (void) signal (SIGALRM, alarmtrap);
  379. #endif
  380. }
  381.